#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Task.hpp"
#include <vector>
#include <queue>

using namespace mythread;
template <class T>
class ThreadPool;

template<class T = Task>
class ThreadData
{
public:
    ThreadData(ThreadPool<T>* threadpool, const std::string& name): _threadpool(threadpool)
    {}
public:
    ThreadPool<T>* _threadpool;
    std::string _name;
};


template <class T = Task>
class ThreadPool
{
    const static size_t g_size = 5;

private:
    static void *handlerTask(void *args)
    {
        // ThreadPool<T> *pthreadpool = static_cast<ThreadPool<T> *>(args);
        ThreadData<T>* td = static_cast<ThreadData<T>*>(args);

        while (true)
        {
            T t;
            {
                LockGuard lockguard(&td->_threadpool->_mutex);
                while (td->_threadpool->isQueueEmpty())
                    td->_threadpool->threadWait();
                td->_threadpool->pop(&t);// pop的本质就是将任务从共享队列中拿到线程自己栈结构中
            }
            
            std::string result = t(); // 处理任务
            std::cout << td->_name << " 获取了一个任务：" << t.toTaskString() << " 并处理完成，结果是：" << result << std::endl;
        }

        delete td;
        return nullptr;
    }

public:
    // void lockQueue() { pthread_mutex_lock(&_mutex); }
    // void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    bool isQueueEmpty() const { return _task_queue.empty(); }
    void threadWait() { pthread_cond_wait(&_cond, &_mutex); }
    void pop(T *t)
    {
        *t = _task_queue.front();
        _task_queue.pop();
    }

public:
    ThreadPool(const size_t size = g_size) : _size(size)
    {
        _threads.reserve(_size);

        for (int i = 0; i < _size; ++i)
            _threads.push_back(new Thread());

        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }
    void run()
    {
        for (const auto &t : _threads)
        {
            ThreadData<T>* td = new ThreadData<T>(this, t->thread_name());
            t->start(handlerTask, td);
            std::cout << t->thread_name() << " run ..." << std::endl;
        }
    }

    void join()
    {
        for (const auto &t : _threads)
        {
            t->join();
        }
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (const auto &t : _threads)
            delete t;
    }

private:
    size_t _size;                   // 线程池中线程个数
    std::vector<Thread *> _threads; // 队列集
    std::queue<T> _task_queue;      // 任务队列
    pthread_mutex_t _mutex;         // 互斥锁
    pthread_cond_t _cond;           // 条件变量
};